package org.atlantis.grosbeak.depot.proxy;

import org.atlantis.grosbeak.depot.DepotException;
import org.atlantis.grosbeak.depot.DepotMaker;
import org.atlantis.grosbeak.depot.EventTrigger;
import org.atlantis.grosbeak.depot.desc.EventDesc;
import org.atlantis.grosbeak.depot.desc.FieldDesc;
import org.atlantis.grosbeak.depot.desc.ObjectDesc;
import org.atlantis.grosbeak.depot.weaver.DynamicWeaver;
import org.atlantis.grosbeak.depot.weaver.FieldInjector;
import org.atlantis.grosbeak.depot.weaver.StaticWeaver;
import org.atlantis.grosbeak.lang.Exceptions;
import org.atlantis.grosbeak.lang.Mirror;
import org.atlantis.grosbeak.lang.Strings;

/**
 * 默认的对象代理生成器。它会根据对象描述（ObjectDesc）来生成一个对象代理。
 * 
 * @author <a href="mailto:seenoevil.cn@gmail.com">SeeNoEvil</a>
 * 
 */
public class DefaultObjectProxyMaker implements ObjectProxyMaker {

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.atlantis.grosbeak.depot.proxy.ObjectProxyMaker#make(org.atlantis.
	 * grosbeak.depot.DepotMaker, org.atlantis.grosbeak.depot.desc.ObjectDesc)
	 */
	public ObjectProxy make(DepotMaker maker, ObjectDesc od) {
		Mirror<?> mirror = Mirror.me(od.getType());
		ObjectProxy op = new ObjectProxy();
		if (od.isSingleton() && null != maker.getId())
			maker.getEnv().save(od.getScope(), maker.getId(), op);
		try {
			DynamicWeaver dw = null;
			if (od.isSingleton())
				dw = new StaticWeaver();
			else
				dw = new DynamicWeaver();

			// 建立对象的事件触发器
			if (null != od.getEvent()) {
				EventDesc ed = od.getEvent();
				op.setObtain(createTrigger(ed.getObtain()));
				dw.setCreate(createTrigger(ed.getCreate()));
				dw.setDestroy(createTrigger(ed.getDestroy()));
			}

			// 构造方法的参数
			ValueProxy[] vps = new ValueProxy[od.getArgs().length];
			for (int i = 0; i < vps.length; i++) {
				vps[i] = maker.makeValue(od.getArgs()[i]);
			}
			dw.setArgs(vps);

			Object[] args = new Object[vps.length];
			for (int i = 0; i < args.length; i++)
				args[i] = vps[i].get(maker);

			// 缓存构造方法
			dw.setFruiting(mirror.getFruitint(false, args));

			// 获得每个字段的注入方式
			FieldInjector[] fis = new FieldInjector[od.getFields().length];
			for (int i = 0; i < fis.length; i++) {
				FieldDesc fd = od.getFields()[i];
				ValueProxy vp = maker.makeValue(fd.getValue());
				fis[i] = FieldInjector.instance(mirror, fd.getName(), vp);
			}
			dw.setFields(fis);
			op.setWeaver(dw);
		} catch (Throwable e) {
			throw Exceptions.wrapThrow(DepotException.class, e);
		}
		return op;
	}

	// 创建一个事件。实际上就是根据用户配置的事件实现的全类型（如：org.atlantis.grosbeak.depot.event.CreateEvent）来生成一个对象。
	@SuppressWarnings("unchecked")
	private static EventTrigger<Object> createTrigger(String str) {
		if (!Strings.isBlank(str) && str.contains(".")) {
			try {
				Class<? extends EventTrigger> triggerClazz = (Class<? extends EventTrigger>) Class
						.forName(str);
				return triggerClazz.newInstance();
			} catch (Exception e) {
				throw Exceptions.wrapThrow(DepotException.class, e);
			}
		}
		return null;
	}
}
